package ngat.oss.simulation;

import java.util.*;
import java.rmi.*;
import java.rmi.server.*;
import java.io.*;

import ngat.oss.*;
import ngat.util.*;
import ngat.phase2.*;

import jyd.storable.*;
import jyd.collection.*;

/** Provides a phase2model based on a JYD database.*/
public class BasicPhase2ModelProvider extends UnicastRemoteObject implements Phase2ModelProvider {

    /** The actual Phase2Model.*/
    BasicMemoryPhase2Model model;

    /** JYD Root name.*/
    private String rootName;

    /** Name of the model.*/
    private String modelName;

    /** Date for this model.*/
    private long modelDate;

    /** JYD Root directory.*/
    private File dbDir;

    /**  Create a BasicPhase2ModelProvider on the supplied JYD root and location.*/
    public BasicPhase2ModelProvider(String rootName, File dbDir) throws RemoteException {
        this.rootName = rootName;
        this.dbDir = dbDir;
	model = new BasicMemoryPhase2Model();
    }
    
    /** Set the model-name.*/
    public void setModelName(String mn) { this.modelName = mn;}

    /** Set the model-date.*/
    public void setModelDate(long md) { this.modelDate = md;}

    /** Load the cache for the specified time.*/
    public void loadCache() throws Exception {

	long now = System.currentTimeMillis();

        OSS_Utilities.setDatabaseDir(dbDir);
        OSS_Utilities.setRootName(rootName);

        Root root = OSS_Utilities.fetchRoot();

        model.clear();

        System.err.println("BasicPhase2ModelProvider::Loading phase2 cache...");

        long st = System.currentTimeMillis();
        int np = 0; // count proposals loaded
	int ng = 0; // count groups loaded
	int rg = 0; // count removed groups
        Iterator iTag = root.listAllTags();
        while (iTag.hasNext()) {

            Tag tag = (Tag)iTag.next();
	    
            Iterator iUser = tag.listAllUsers();
            while (iUser.hasNext()) {
		
                User user = (User)iUser.next();
		
                Iterator iProp = user.listAllProposals();
                while (iProp.hasNext()) {

                    KVPair pair = (KVPair)iProp.next();
                    String name = (String)pair.getKey();
                    Path   path = new Path(user.getFullPath(), name);

                    try {

                        Proposal proposal = OSS_Utilities.fetchProposal(path);

                        if (proposal == null) continue;

			//proposals.put(proposal.getFullPath(),proposal);
			
			if (proposal.getExpiryDate() < now)
			    continue;
			
			Iterator ig = proposal.listAllGroups();
			while (ig.hasNext()) {
			    Group grp = (Group)ig.next();
			    ng++;
			    if (grp.getExpiryDate() < now) {
				System.err.println("Should remove: "+grp.getFullPath());
				//ig.remove();
				rg++;
			    }
			}
			model.addProposal(proposal);
                        np++;

                    } catch (Exception e) {
                        // error loading a proposal....
                        e.printStackTrace();
                    }
                }
            }
        }

        long tt = System.currentTimeMillis() - st;
        System.err.println("Loaded "+np+" proposals containing "+ng+" groups in "+(tt/1000)+"S, discarded "+rg+" expired groups");
        //      start = System.currentTimeMillis();

    }

    /** Returns a Phase2Model.*/
    public Phase2Model getPhase2Model() throws RemoteException {
	System.err.println("BasicPhase2ModelProvider::getPhase2Model()");
	return model;
    }

   /** Returns the Name/ID of the provided model.*/
    public String getModelName() throws RemoteException {
	return modelName;
    }

    /** Returns the date for which the provided model is valid.*/
    public long getModelDate() throws RemoteException {
	return modelDate;
    }

    /** Launch a BasicPhase2ModelProvider.*/
    public static void main(String args[]) {

	try {

	    ConfigurationProperties cfg = CommandTokenizer.use("--").parse(args);
	    
	    String root  = cfg.getProperty("root");
	    File   dbdir = cfg.getFile("base");

	    String mn = cfg.getProperty("model-name", root);

	    long md = (ScheduleSimulator.sdf.parse(cfg.getProperty("model-date"))).getTime();

	    BasicPhase2ModelProvider provider = new BasicPhase2ModelProvider(root, dbdir);
	    provider.setModelName(mn);
	    provider.setModelDate(md);
	    provider.loadCache();
	    Naming.rebind("rmi://localhost/"+root+"_Phase2ModelProvider", provider);
	    
	    System.err.println("PhaseModel provider for model: "+mn+", Root: "+root+" bound to registry");
	    
	    // busy wait to keep alive
            while (true) {
                try{Thread.sleep(60000L);} catch (Exception e) {}
            }

	} catch (Exception e) {
	    System.err.println("Usage: BasicPhase2ModelProvider --model-name <mn> --model-date <yyyy-MM-dd HH:mm:ss> --root <root> --base <base-dir>");
	    e.printStackTrace();
	}
    }
    
}
